#ifdef __cplusplus
extern "C"{
#endif
#include "xs_def.h"
#include "xs_network.h"
#include "xs_log.h"
#include "xs_sock.h"
#include "xs_io.h"


int __xs_net_socket__(int __domain, int __type, int __pro)
{
	int __fd__;
	
	__fd__ = socket(__domain, __type, __pro);
	if( __fd__ < 0 ){
		xs_dump_error_str(errno);
		return EXIT_ERROR;
	}

	return __fd__;
}

/*
	__max specifies the queue length for completely established sockets 
	waiting to be accepted, instead of the number of incomplete connection requests.
*/
static inline int __xs_net_listen__(int __f, int __max)
{
	int __result__ = -1;

	__result__ = listen(__f, __max);
	if(__result__ < 0){
		xs_dump_error_str(errno);
		return EXIT_ERROR;
	}
	
	return EXIT_OK;
}

static inline int __xs_net_accept__(int __f,  struct sockaddr *__sa,  socklen_t *__sal)
{
	int __result__ = -1;
	
	if(__sa == NULL) return EXIT_ERROR;
	if(__sa){
		while((__result__ = accept(__f, __sa, __sal)) < 0) {
		
			if(errno == ECONNABORTED || errno == EINTR) continue;
			else{
				xs_dump_error_str(errno);
				return EXIT_ERROR;
			}
		}
	}
	
	return __result__;
}
static inline int __xs_net_bind__(int __f, const struct sockaddr *__sa,  socklen_t __sal)
{
	if(__sa == NULL) return EXIT_ERROR;
	
	if(__sa){
		if (bind(__f, __sa, __sal) < 0){
			xs_dump_error_str(errno);
			return EXIT_ERROR;
		}
	}
	
	return EXIT_OK;
}

static inline int __xs_net_connect__(uint16_t __port,  const char* __ip)
{
    int __fd__;
    int __result__;
    struct sockaddr_in __addr__;

    __fd__ = socket(AF_INET, SOCK_STREAM, 0);
    if(__fd__ < 0) {
        xs_logd("create error");
        return __fd__;
    }

    __addr__.sin_family = AF_INET;
    __addr__.sin_port = htons(__port);

    __addr__.sin_addr = xs_sock_getip(__ip);

    __result__ = connect(__fd__, (struct sockaddr*)&__addr__, sizeof(__addr__));
    if(__result__ < 0  &&  errno != EINPROGRESS) {
        xs_loge("connect error %d", errno);
        xs_close_socket(__fd__);
        return __result__;
    }
	
    return __fd__;
}
	
static inline int __xs_net_send__(int __f, void *__p, size_t __s, int __flags)
{
	int __len__ = -1;

	while((__len__ = send(__f, __p, __s, __flags)) == -1) {
		if(errno == EINTR) continue;
		else{
			__len__ = -1;
			break;
		}
	}

	return __len__;
}

static inline int __xs_net_recv__(int __f, void *__p, size_t __s, int __flags)
{
	int __len__ = -1;

	while((__len__ = recv(__f, __p, __s, __flags)) == -1) {
		if(errno == EINTR) continue;
		else{
			//xs_logd("recv < 0");
			__len__ = -1;
			break;
		}
	}
	
	return __len__;	
}

int xs_net_socket(int __family, int __type, int __pro)
{
	return (__xs_net_socket__(__family, __type, __pro));
}
	
int xs_net_bind(int __f, const struct sockaddr *__sa,  socklen_t __sal)
{
	return (__xs_net_bind__(__f, __sa, __sal));
}
int xs_net_listen(int __f, int __max)
{
	return (__xs_net_listen__(__f, __max));
}
int xs_net_accept(int __f,  struct sockaddr *__sa,  socklen_t *__sal)
{
	return (__xs_net_accept__(__f,  __sa,  __sal));
}
int xs_net_connect(u_int16_t __port, const char* __ip)
{
	return (__xs_net_connect__(__port, __ip));
}

//#define __READ_WRITE__API__
int xs_net_send(int __f, void *__p, int __s)
{
#ifdef __READ_WRITE__API__
	return __xs_write_n__(__f, __p, __s);
#else
	return __xs_net_send__(__f, __p, __s, 0);
#endif
}

int xs_net_recv(int __f, char *__p, int __s)
{
#ifdef __READ_WRITE__API__
	return __xs_read_n__(__f, __p, __s);
#else
	return __xs_net_recv__(__f, __p, __s, 0);
#endif
}

int xs_close_socket(int __f)
{
	return xs_release_socket(__f);
}

/* __dna is an ip string 
	__p is a port */
int xs_create_connect(const char* __dna, short int __p)
{
	return (xs_sock_connect(__p, __dna));
}

/* __dna is an ip string 
	__p is a port */
int xs_create_server(const char *__dna, short int __p)
{
	int server_socket = -1;
	struct sockaddr_in *server_addr;  
	
	server_addr = malloc(sizeof(struct sockaddr_in));  
	server_addr->sin_family = AF_INET;  
	if(__dna == NULL)	
		server_addr->sin_addr.s_addr = htons(INADDR_ANY); 
	else
		server_addr->sin_addr = xs_sock_getip(__dna);
	
	server_addr->sin_port = htons(__p);  
	server_socket = xs_net_socket(AF_INET, SOCK_STREAM, 0);  
	set_nonblocking(server_socket);  

	xs_net_bind(server_socket,(struct sockaddr*)server_addr,sizeof(struct sockaddr_in));
	xs_net_listen(server_socket, xs_default_listen_size); 

	return server_socket;  
}

#ifdef __cplusplus
}
#endif
